package com.mop.core.es.dao.plugins.wraper;

import com.lemon.core.common.lang.annotation.Nullable;
import com.lemon.core.common.lang.util.Assert;
import com.mop.core.es.dao.util.ESHelper;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @author lemon
 * @ClassName QueryWraper
 * @desc
 * @Date 2019/1/5 16:18
 * @Version 1.0
 **/
public class QueryWraper<T> {

    private Integer start;

    private Integer end;

    private Boolean isAggs = false;

    private T entity;

    private List<String> includesList = new LinkedList<String>();

    private List<String> excludesList = new LinkedList<String>();

    /**
     * 高亮
     */
    private HighlightBuilder highlightBuilder = new HighlightBuilder();

    /**
     * 查询构造器
     */
    private BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

    /**
     * 检索构造器
     */
    private SearchSourceBuilder searchSourceBuilder = ESHelper.getSearchSourceBuilder();

    // -------------------- 命中结果过滤 --------------------

    public void match(@Nullable String field, Object value) {
        queryBuilder.must(QueryBuilders.matchQuery(field, value));
    }

    public void matchPhrase (@Nullable String field, Object value) {
        queryBuilder.must(QueryBuilders.matchPhraseQuery(field, value));
    }

    public void gt(@Nullable String field, Object value) {
        queryBuilder.must(QueryBuilders.rangeQuery(field).gt(value));
    }

    public void gte(@Nullable String field, Object value) {
        queryBuilder.must(QueryBuilders.rangeQuery(field).gte(value));
    }

    public void lt(@Nullable String field, Object value) {
        queryBuilder.must(QueryBuilders.rangeQuery(field).lt(value));
    }

    public void lte(@Nullable String field, Object value) {
        queryBuilder.must(QueryBuilders.rangeQuery(field).lte(value));
    }

    public void exists(@Nullable String field) {
        queryBuilder.must(QueryBuilders.existsQuery(field));
    }

    public void notExists(@Nullable String field) {
        queryBuilder.mustNot(QueryBuilders.existsQuery(field));
    }

    /*public void missing(String field) {
        queryBuilder.must(QueryBuilders.boolQuery().mustNot(this.exists(field)));
    }*/

    public void orderBy(@Nullable String field, @Nullable SortOrder sortOrder) {
        searchSourceBuilder.sort(field, sortOrder);
    }

    public void orderByAsc(@Nullable String... fields) {
        for (String field : fields) {
            searchSourceBuilder.sort(field, SortOrder.ASC);
        }
    }

    public void orderByDesc(@Nullable String... fields) {
        for (String field : fields) {
            searchSourceBuilder.sort(field, SortOrder.DESC);
        }
    }

    // -------------------- 命中结果过滤 --------------------




    // ---------------------- 聚合操作 ----------------------

    public void terms(@Nullable String field) {
        searchSourceBuilder.aggregation(AggregationBuilders.terms("terms_aggs").field(field));
    }

    public void max(@Nullable String field) {
        searchSourceBuilder.aggregation(AggregationBuilders.max("max_aggs").field(field));
    }

    public void min(@Nullable String field) {
        searchSourceBuilder.aggregation(AggregationBuilders.min("min_aggs").field(field));
    }

    public void sum(@Nullable String field) {
        searchSourceBuilder.aggregation(AggregationBuilders.sum("sum_aggs").field(field));
    }

    public void count(@Nullable String field) {
        searchSourceBuilder.aggregation(AggregationBuilders.count("count_aggs").field(field));
    }

    public void avg(@Nullable String field) {
        searchSourceBuilder.aggregation(AggregationBuilders.avg("avg_aggs").field(field));
    }

    // ---------------------- 聚合操作 ----------------------

    public void includes(String... includes) {
        includesList.addAll(Arrays.asList(includes));
    }

    public void excludes(String... excludes) {
        excludesList.addAll(Arrays.asList(excludes));
    }

    // ---------------------- 高亮操作 ----------------------

    public void preTags(String... preTags) {
        highlightBuilder.preTags(preTags);
    }

    public void postTags(String... postTags) {
        highlightBuilder.postTags(postTags);
    }

    public void highlight(@Nullable String field) {
        highlightBuilder.field(field);
    }

    // ---------------------- 高亮操作 ----------------------


    public QueryWraper() {
    }

    public QueryWraper(T entity) {
        this.entity = entity;
    }

    public Integer getStart() {
        return start;
    }

    public void setStart(Integer start) {
        this.start = start;
    }

    public Integer getEnd() {
        return end;
    }

    public void setEnd(Integer end) {
        this.end = end;
    }

    public Boolean isAggs() {
        return isAggs;
    }

    public void setIsAggs(Boolean aggs) {
        isAggs = aggs;
    }

    public T getEntity() {
        Assert.notNull(entity, "entity不可为空!");
        return entity;
    }

    public void setEntity(@Nullable T entity) {
        ESHelper.setClazzMustBoolBuilder(queryBuilder, entity);
        this.entity = entity;
    }

    public void setQueryBuilder(@Nullable BoolQueryBuilder queryBuilder) {
        this.queryBuilder = queryBuilder;
    }

    public BoolQueryBuilder getQueryBuilder() {
        return queryBuilder;
    }

    public void setSearchSourceBuilder(@Nullable SearchSourceBuilder searchSourceBuilder) {
        this.searchSourceBuilder = searchSourceBuilder;
    }

    public SearchSourceBuilder getSearchSourceBuilder() {
        if (isAggs) {
            searchSourceBuilder.size(0);
        }
        if (highlightBuilder.fields().size() > 0) {
            searchSourceBuilder.highlighter(highlightBuilder);
        }
        if (includesList.size() > 0 || excludesList.size() > 0) {
            String[] includeAry = includesList.toArray(new String[includesList.size()]);
            String[] excludeAry = excludesList.toArray(new String[excludesList.size()]);
            searchSourceBuilder.fetchSource(includeAry, excludeAry);
        }
        searchSourceBuilder.size(10);
        return searchSourceBuilder.query(queryBuilder);
    }

    public static void main(String[] args) {
        QueryWraper queryWraper = new QueryWraper();
        queryWraper.terms(null);
    }
}
